#include "cellBase.hpp"
#include "meshTypes.hpp"

namespace hms {

#define REQUIRE_MEMBER_FUNC(FUNC_NAME) \
	static_assert(std::is_member_function_pointer_v< \
		decltype(&CellType::FUNC_NAME) \
	>);

#define CHEAD(RETURN_TYPE) \
template<typename CellType> RETURN_TYPE CellBase<CellType>::

/* the constructor checks for existence (but not correctness) of interface
 * implementations during compile time */
CHEAD() CellBase(){
	REQUIRE_MEMBER_FUNC(mesh)
	REQUIRE_MEMBER_FUNC(index)
	// REQUIRE_MEMBER_FUNC(area)
	// REQUIRE_MEMBER_FUNC(circumf)
	// REQUIRE_MEMBER_FUNC(centroid)
	REQUIRE_MEMBER_FUNC(edges)
	REQUIRE_MEMBER_FUNC(edge)
	REQUIRE_MEMBER_FUNC(nEdges)
	REQUIRE_MEMBER_FUNC(isGhost)
	REQUIRE_MEMBER_FUNC(domainCell)
	REQUIRE_MEMBER_FUNC(isBoundary)
	REQUIRE_MEMBER_FUNC(vertices)
}


#define FORWARD_FUNC_CALL_NOARG(NAME,RET) \
	CHEAD(auto) NAME() const -> RET { \
		return this->derived().NAME##Imp(); \
	}

FORWARD_FUNC_CALL_NOARG(mesh      , const MeshType&)
FORWARD_FUNC_CALL_NOARG(index     , Index)
FORWARD_FUNC_CALL_NOARG(area      , scalar)
FORWARD_FUNC_CALL_NOARG(circumf   , scalar)
FORWARD_FUNC_CALL_NOARG(centroid  , CentroidType)
FORWARD_FUNC_CALL_NOARG(edges     , EdgeIndices)
FORWARD_FUNC_CALL_NOARG(edge      , Index)
FORWARD_FUNC_CALL_NOARG(nEdges    , char)
FORWARD_FUNC_CALL_NOARG(isGhost   , bool)
FORWARD_FUNC_CALL_NOARG(domainCell, CellType)
FORWARD_FUNC_CALL_NOARG(isBoundary, bool)
FORWARD_FUNC_CALL_NOARG(neighbours, ArrayXi)

CHEAD(auto) vertices(bool ordered) const ->
	ArrayXi
{
	return this->derived().verticesImp(ordered);
}

// CHEAD(auto) area() const -> scalar {
// 	return mesh().cells().areas()( index() );
// }

// CHEAD(auto) circumf() const -> scalar {
// 	return mesh().cells().circumfs()( index() );
// }

// CHEAD(auto) centroid() const -> CentroidType {
// 	return mesh().cells().centroids().col( index() );
// }

#undef CHEAD
#undef REQUIRE_MEMBER_FUNC
#undef FORWARD_FUNC_CALL_NOARG

template class CellBase<Cell>;
template class CellBase<UniCell>;
template class CellBase<RectCell>;
template class CellBase<StructCell>;

} // end namespace hms